/*
 * @Author: your name
 * @Date: 2022-04-07 14:10:13
 * @LastEditTime: 2022-04-07 15:53:28
 * @LastEditors: Please set LastEditors
 * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 * @FilePath: /comic-algorithm/chapter06/6.5.js
 */
/**
|--------------------------------------------------
| 如何实现红包算法
  需求
     1.所有红包金额之和等于总金额
     2.每个人至少抢到1分钱
     3.保证红包拆分尽可能均匀，不能出现二级分化太严重
|--------------------------------------------------
*/
// min ≤ r ≤ max
function Random(min, max) {
  return Math.round(Math.random() * (max - min)) + min;
}
// 2.二倍均值法
// 这是一种很合理很公平的抢红包算法了
// 在此我们假设
// 红包剩余金额为 M
// 红包剩余数量为 N
// 这种算法就是每次都在区间[0,M/N×2] 随机取一个数
// 假设100元红包发10个人，那么合理的做法应该是每个人领到10元的概率相同。
// 第一个人随机金额的范围为[0,100/10×2] ,也就是[0,20],这样平均可以领到10元，此时剩余金额为100-10=90。
// 第二个人随机金额的范围为[0,90/9×2] ,也就是[0,20],这样平均也可以领到10元，此时剩余金额为90-10=80。
// 第三个人随机金额的范围为[0,80/8×2] ,也就是[0,20],这样平均也可以领到10元。
function divideRedPackage(totalAmount, totalPeopleNum) {
  let restAmount = totalAmount;
  let restPeopleNum = totalPeopleNum;
  let amountList = [];
  for (let i = 0; i < totalPeopleNum - 1; i++) {
    //随机范围 【0.01,xx.99】
    let amount = Random(0.01, (restAmount / restPeopleNum) * 2 - 0.01);
    //减去金额
    restAmount -= amount;
    // 减去人数
    restPeopleNum--;
    amountList.push(amount);
  }
  //剩余最后一个的金额
  amountList.push(restAmount);
  return amountList;
}

const amountList = divideRedPackage(1000, 11);
console.log('抢到的金额是：', amountList);

/**
 * 线性切割
 * 当时的代码处理还很简单，先从普通场景探索下红包问题

拼手气红包--线性切割法 
    场景:100块钱红包，群内50人，红包数量为20个，30个人将抢不到红包

 这个算法可以把总金额想象成一条线段，每个人都有机会切一刀，
 前面的人切完(有失公平性，会出现第一个切一大段的情况，后面需要改造)，
 剩下的后面的人再接着切剩下的，
 这样越是前面的人截取的长度（理解成领取到的红包金额）越大的概率就越大。
 */
function lineSegmentCutting(totalAmount, totalPeopleNum) {
  let begin = 0.01,
    end = totalAmount;
  let y = 0;
  let amountList = [];
  for (let i = 0; i < totalPeopleNum - 1; i++) {
    let nn = 0;
    let amount = Random(begin, end);
    nn = amount - begin;
    console.log('第' + (i + 1) + '个人领取的红包金额为：' + nn);
    y += nn;
    begin = amount;
    amountList.push(nn);
  }
  console.log('第' + totalPeopleNum + '个人领取的红包金额为：', parseInt(end - begin - 0.01));
  console.log('线段切割法手气最佳！！！' + 'max');
  y += end - begin + 0.01;
  console.log('验证发出的红包总金额为：' + y);
  return amountList;
}
const amountList2 = lineSegmentCutting(101, 5);
console.log('抢到的金额是：', amountList2);
